package fr.asip.cps3.exemple.modele.traitements.fonctionsPKCS11.slotscartes;

import iaik.pkcs.pkcs11.wrapper.CK_MECHANISM_INFO;
import iaik.pkcs.pkcs11.wrapper.CK_TOKEN_INFO;
import iaik.pkcs.pkcs11.wrapper.PKCS11;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;

import java.util.LinkedHashMap;

import org.apache.log4j.Logger;

import fr.asip.cps3.exemple.modele.exceptions.ExceptionProgrammeExemple;
import fr.asip.cps3.exemple.modele.exceptions.ExceptionTraitement;
import fr.asip.cps3.exemple.modele.resultats.Resultat;
import fr.asip.cps3.exemple.modele.resultats.ResultatInfo;
import fr.asip.cps3.exemple.modele.traitements.util.TraitementsUtil;

/**
 * Classe de traitement : Obtention des informations sur l'algorithme
 *
 */
public class InfoAlgo{

	/**
	 * Le loggeur
	 */
	private static Logger log = Logger.getLogger(InfoAlgo.class);
	
	/**
	 * Renvoie le résultat de l'opération
	 * @param librairie Librairie PKCS#11 à utiliser
	 * @param idSlotToken Identifiant du slot hébergeant la carte
	 * @param idAlgo Identifiant de l'algorithme
	 * @return Résultat de l'opération
	 * @throws ExceptionTraitement 
	 */
	public static Resultat traitementP11(PKCS11 librairie, long idSlotToken, long idAlgo) throws ExceptionTraitement {

		try {
		
			if(librairie != null) {		
		
				ResultatInfo resultat = new ResultatInfo("Obtenir des informations sur l'algorithme ");
				LinkedHashMap<String,String> infos = new LinkedHashMap<String,String>();
				resultat.setInfos(infos);
				
				try {
					
					// Récupération du libellé de la carte
					CK_TOKEN_INFO info = librairie.C_GetTokenInfo(idSlotToken);
					if(info != null)
						resultat.appendTraitement(TraitementsUtil.getNomAlgo(idAlgo).replaceAll("_", " ").replaceAll("CKM", "").trim()+" de la carte "+new String(info.label).trim()+" (C_GetMechanismInfo)");
					else
						resultat.appendTraitement("(C_GetMechanismInfo)");
					
				} catch (PKCS11Exception e) {
					
					// On ne fait rien, il ne s'agit pas de la fonction que l'on teste dans ce traitement
					
				}
					
				// Récupération des informations sur l'algorithme
				try {
		
					// Traitement à tester
					CK_MECHANISM_INFO info = librairie.C_GetMechanismInfo(idSlotToken,idAlgo);
					
					if(info != null) {
						
						// Formatage du resultat
						infos.put("Taille minimale de la clé pour l'algorithme (l'unité de grandeur (bits ou octets) dépend du type d'algorithme)?",Long.toString(info.ulMinKeySize));
						infos.put("Taille maximale de la clé pour l'algorithme (l'unité de grandeur (bits ou octets) dépend du type d'algorithme)?",Long.toString(info.ulMaxKeySize));
						infos.put("L'algorithme est-il directement appliqué sur la carte?",(info.flags & PKCS11Constants.CKF_HW)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour le chiffrement?",(info.flags & PKCS11Constants.CKF_ENCRYPT)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour le déchiffrement?",(info.flags & PKCS11Constants.CKF_DECRYPT)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour réaliser un condensat?",(info.flags & PKCS11Constants.CKF_DIGEST)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour réaliser une signature?",(info.flags & PKCS11Constants.CKF_SIGN)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour récupérer une donnée depuis une signature?",(info.flags & PKCS11Constants.CKF_SIGN_RECOVER)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour réaliser la vérification d’une signature ou d’un MAC (Message Authentication Code)?",(info.flags & PKCS11Constants.CKF_VERIFY)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour réaliser la vérification d’une signature ou d’un MAC (Message Authentication Code) avec récupération de la donnée depuis la signature?",(info.flags & PKCS11Constants.CKF_VERIFY_RECOVER)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour générer une clé secrète?",(info.flags & PKCS11Constants.CKF_GENERATE)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour générer une paire de clés (publique/privée)?",(info.flags & PKCS11Constants.CKF_GENERATE_KEY_PAIR)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour chiffrer une clé?",(info.flags & PKCS11Constants.CKF_WRAP)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour déchiffrer une clé?",(info.flags & PKCS11Constants.CKF_UNWRAP)!=0?"Oui":"Non");
						infos.put("L'algorithme peut-il être utilisé pour dériver une clé depuis une autre clé?",(info.flags & PKCS11Constants.CKF_DERIVE)!=0?"Oui":"Non");
					
					} else {
						
						// Si les informations sont nulles on lève l'exception
						log.error("L'operation a retourne des informations nulles");
						throw new ExceptionTraitement(ExceptionProgrammeExemple.TYPE_TRAITEMENT_SLOTSCARTES_LISTE_ALGO, "L'opération a retourné des informations nulles");
						
					}
		
				} catch (PKCS11Exception e) {
					
					log.info("Operation echouee : "+TraitementsUtil.retranscritCodeRetour(e.getErrorCode()));
					resultat.setCodeRetour(e.getErrorCode());
					
				}
		
				return resultat;
				
			} else {
	
				// Si la librairie est nulle il est impossible de réaliser l'opération
				log.error("La librairie est nulle");
				throw new ExceptionTraitement(ExceptionProgrammeExemple.TYPE_TRAITEMENT_SLOTSCARTES_INFO_ALGO, "La librairie est nulle");
				
			}
			
		} catch (Throwable t) {
			
			// Si une erreur Traitement a été rencontrée on lève l'exception
			if(t instanceof ExceptionTraitement)
				throw (ExceptionTraitement)t;
			
			// Si une erreur inattendue est survenue on la logue et on la lève
			log.error("Une erreur inattendue est survenue : "+ExceptionProgrammeExemple.getStacktrace(t));
			throw new ExceptionTraitement(ExceptionProgrammeExemple.TYPE_TRAITEMENT_SLOTSCARTES_INFO_ALGO, "Une erreur inattendue est survenue");
			
		}
				
	}

}
